﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine.UI;

public class GameStateManager : MonoBehaviour {

	public List<GameObject> rooms = new List<GameObject>();
	public List<GameObject> enemyTypes = new List<GameObject>();
	public int level = 0;
	public GameObject player;
	GameObject loseScreen;
	GameObject normalUI;
	GameObject mapUI;
	GameObject mapBack;
	GameObject playerIcon;
	public RenderTexture miniMap;
	bool firstStart = true;
	int currentRoom = 0;
	public int roomsCleared = 0;
	public int secretsRooms = 0;
	public int enemiesKilled = 0;
	int seed;
	public bool lost = false;
	bool enabledState = false;
	public Inventory inventoryObj;
	public bool mapUpdated = true;
	float textTimer = 0.04f;
	NetworkView nv;
	void Start () {
		nv = GetComponent<NetworkView>();
		miniMap = GameObject.Find("UIcam").GetComponent<Camera>().targetTexture;
		playerIcon = transform.Find("PlayerLocMap").gameObject;
		loseScreen = GameObject.Find ("LoseScreen");
		loseScreen.SetActive (false);
		normalUI = GameObject.Find ("Canvas");
		mapBack = player.transform.Find ("MapBack").gameObject;
		mapUI = player.transform.Find ("Map").gameObject;
		if (GameObject.FindGameObjectsWithTag ("StateManager").Length > 1) {
			Destroy (gameObject);
			return;
		}
		if (firstStart) {
			RenderSettings.ambientLight = new Color (0, 0, 0, 0);
			if (!Load ()) {
				seed = UnityEngine.Random.seed;
				Save ();
			}
			inventoryObj.GetComponent<Inventory> ().UpdateGrid ();
			inventoryObj.GetComponent<Inventory> ().AfterLoad ();
			UnityEngine.Random.seed = seed + level;
			DontDestroyOnLoad (gameObject);
			firstStart = false;
		}
	}
	void OnLevelWasLoaded(int level) {
		textTimer = 0.03f;
		miniMap = GameObject.Find("UIcam").GetComponent<Camera>().targetTexture;
		playerIcon = transform.Find("PlayerLocMap").gameObject;
		playerIcon.transform.position = Vector3.zero;
		if(!firstStart) {
			player = GameObject.FindGameObjectWithTag ("Player");
			loseScreen = GameObject.Find ("LoseScreen");
			loseScreen.SetActive(false);
			normalUI = GameObject.Find ("Canvas");
			mapBack = player.transform.Find ("MapBack").gameObject;
			mapUI = player.transform.Find ("Map").gameObject;
			inventoryObj.holder = GameObject.Find ("Canvas").transform.Find ("Handler").gameObject.GetComponent<RectTransform>();
			inventoryObj.AfterLevelLoad();
			inventoryObj.GenerateSlots();
			inventoryObj.UpdateGrid ();
			currentRoom = 0;
		}
	}

	public void ChangeRoom(GameObject room, bool first = false) {
		if(enabledState) {
			mapUpdated = true;
			rooms[currentRoom].GetComponent<Room>().TurnLightsOff();
			currentRoom = rooms.IndexOf(room);
			rooms[currentRoom].GetComponent<Room>().TurnLightsOn();
			room.GetComponent<Room>().roomCleared = false;
			room.GetComponent<Room>().CloseDoors();
			room.GetComponent<Room>().EnableEnemies();
			room.GetComponent<Room>().UpdateEnemies();
			playerIcon.transform.position = room.transform.position + new Vector3(0, 1, 0);
			textTimer = 0.03f;
		}
	}
	public void Enable() {
		enabledState = true;
		SendTexture();
		foreach (GameObject room in rooms) {
			if(room.name != "InitialRoom") {
				room.GetComponent<Room>().SpawnEnemies(4, enemyTypes);
			}
		}
	}
	public void AdvanceLevel() {
		level++;
		UnityEngine.Random.seed = seed + level;
		Save ();
		currentRoom = 0;
		Application.LoadLevel (Application.loadedLevel);
		/*inventoryObj.holder = GameObject.Find ("Canvas").transform.Find ("Handler").gameObject.GetComponent<RectTransform>();
		inventoryObj.slots.Clear();
		inventoryObj.GenerateSlots();
		inventoryObj.UpdateGrid ();
		inventoryObj.AfterLevelLoad();
		currentRoom = 0;
		player = GameObject.FindGameObjectWithTag ("Player");*/
	}
	public void Update() {
		if (player.GetComponent<Player> ().health <= 0 && !lost)
			Lose ();
		if (Input.GetKeyDown (KeyCode.X)) {
			DeleteSave();
		}
		if(textTimer > 0)
		textTimer -= Time.deltaTime;
		else {
			SendTexture();
			textTimer = Mathf.Infinity;
		}
	}
	public void Save() {
		BinaryFormatter bf = new BinaryFormatter ();
		FileStream file;
		file = File.Open (Application.persistentDataPath + "/saveData.dat", FileMode.Create);
		SaveData data = new SaveData ();
		data.level = level;
		data.inventory = inventoryObj.items;
		data.seed = seed;
		bf.Serialize (file, data);
		file.Close ();
	}
	public bool Load() {
		if (!File.Exists (Application.persistentDataPath + "/saveData.dat")) return false;
		BinaryFormatter bf = new BinaryFormatter ();
		FileStream file;
		file = File.Open (Application.persistentDataPath + "/saveData.dat", FileMode.Open);
		SaveData data = (SaveData)bf.Deserialize (file);
		file.Close ();
		level = data.level;
		seed = data.seed;
		inventoryObj.items = data.inventory;
		return true;
	}
	public void DeleteSave() {
		File.Delete (Application.persistentDataPath + "/saveData.dat");
	}
	public void Lose() {
		DeleteSave ();
		normalUI.SetActive (false);
		loseScreen.SetActive (true);
		mapUI.SetActive(false);
		mapBack.SetActive (false);
		Time.timeScale = 0;
		player.GetComponent<CharacterMovement> ().enabled = false;
		player.transform.Find ("Torso").GetComponent<Weapon> ().enabled = false;
		inventoryObj.GetComponent<Inventory> ().fillGrid ();
		loseScreen.transform.Find ("Panel").transform.Find("Panel").transform.Find ("Stats").GetComponent<Text> ().text = "Rooms cleared: " + roomsCleared + 
				"\n Secrets Found: " + secretsRooms +
				"\nEnemies Killed: " +enemiesKilled;
		lost = true;
	}
	public void Restart() {
		DeleteSave ();
		Time.timeScale = 1;
		Application.LoadLevel (Application.loadedLevel);
		Destroy (gameObject);
	}
	void SendTexture() {
		Debug.Log("Sent textures");
		RenderTexture rt = GetComponent<GameStateManager>().miniMap;
		RenderTexture.active = rt;
		Texture2D tex = new Texture2D (rt.width, rt.height);
		tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
		tex.Apply();
		byte[] bytes = tex.EncodeToPNG ();
		CutArray(bytes);
	}
	void CutArray(byte[] bytes){
		if(bytes.Length > 2048) {
			byte[] temp = new byte[2048];
			Array.Copy(bytes,0, temp, 0, 2048);
			nv.RPC("TransferTexture", RPCMode.OthersBuffered, Convert.ToBase64String(temp),0);
			byte[] temp2 = new byte[bytes.Length-2048];
			Array.Copy(bytes,2048, temp2, 0, bytes.Length-2048);
			CutArray(temp2);
		}
		else {
			nv.RPC("TransferTexture", RPCMode.OthersBuffered, Convert.ToBase64String(bytes),1);
		}
	}
	[RPC]
	void TransferTexture(string bytes, int complete){
	
	}
}
[Serializable]
class SaveData {
	public int level;
	public int seed;
	public List<Inventory.InventoryItem> inventory;
}

